package cn.t.facade.user;


import cn.t.converter.user.ParticipantRoleDTOConverter;
import cn.t.converter.user.RoleInfoDTOConverter;
import cn.t.core.exception.BizException;
import cn.t.core.facade.FacadeImpl;
import cn.t.core.mode.BaseDTO;
import cn.t.dto.user.ParticipantRoleDTO;
import cn.t.dto.user.RoleInfoDTO;
import cn.t.dto.user.UserInfoDTO;
import cn.t.core.enums.base.CommonError;
import cn.t.enums.user.UpdateEventTypeEnum;
import cn.t.model.user.ParticipantInfoDO;
import cn.t.model.user.ParticipantRoleDO;
import cn.t.model.user.RoleInfoDO;
import cn.t.model.user.UserInfoDO;
import cn.t.service.user.ParticipantInfoService;
import cn.t.service.user.ParticipantRoleService;
import cn.t.service.user.RoleInfoService;
import cn.t.service.user.UserInfoService;
import cn.t.user.event.UserQueryUpdateEvent;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 参与者和角色关联表服务编排
 *
 * @author l
 */
@Slf4j
@Service
@AllArgsConstructor
public class ParticipantRoleFacade extends FacadeImpl<ParticipantRoleDTO, ParticipantRoleDO, ParticipantRoleDTOConverter, ParticipantRoleService> {

    @Transactional
    public void assignRights(UserInfoDTO userInfoDTO, List<RoleInfoDTO> roleInfoDtoList) {

        UserInfoDO userInfoDO = userInfoService.findById(userInfoDTO.getId());
        if (userInfoDO == null || !userInfoDO.getId().equals(userInfoDTO.getId())) {
            String errorMessage = String.format("用户不存在 用户ID：%d ", userInfoDTO.getId());
            log.error(errorMessage);
            throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
        }

        List<ParticipantInfoDO> exists = this.participantInfoService.findByUserId(userInfoDO.getId());
        Set<Long> existsParticipantIds = null;
        // key = firmId
        Map<Long, ParticipantInfoDO> firmMap = null;

        // 删除所有权限
        if (!CollectionUtils.isEmpty(exists)) {
            existsParticipantIds = exists.stream().map(ParticipantInfoDO::getId).collect(Collectors.toSet());
            firmMap = exists.stream().collect(Collectors.toMap(ParticipantInfoDO::getFirmId, participant -> participant));
            removeMenu(existsParticipantIds);
        }

        if (CollectionUtils.isEmpty(roleInfoDtoList)) {
            // 没有需要新增的权限
            return;
        }

        // 添加权限
        if (firmMap == null) {
            firmMap = new HashMap<>();
        }
        List<RoleInfoDO> roleInfoList = roleInfoDtoList.stream().map(roleInfoDTOConverter::dto2Model).collect(Collectors.toList());

        roleInfoList = roleInfoService.fullFill(roleInfoList);

        for (RoleInfoDO roleInfoDO : roleInfoList) {
            firmMap = service.addRole(userInfoDO, roleInfoDO, firmMap);
        }
        applicationEventPublisher.publishEvent(new UserQueryUpdateEvent(userInfoDO.getId(), userSessionFacade.operatorInfo(), userInfoDO.getId(), UpdateEventTypeEnum.UPDATE, UpdateEventTypeEnum.UPDATE, UpdateEventTypeEnum.UPDATE));
    }

    private void removeMenu(Set<Long> participantIds) {
        if (CollectionUtils.isEmpty(participantIds)) {
            return;
        }

        for (Long participantId : participantIds) {
            service.removeMenuByParticipantId(participantId);
        }

    }


    public static boolean isResourceSame(List<? extends BaseDTO> aList, List<? extends BaseDTO> bList) {
        if (aList == null && bList == null) {
            return true;
        }

        if ((aList == null && bList != null) || (aList != null && bList == null)) {
            return false;
        }

        if (aList.size() != bList.size()) {
            return false;
        }

        List<Long> aResourceIds = aList.stream().map(BaseDTO::getId).collect(Collectors.toList());
        List<Long> bResourceIds = bList.stream().map(BaseDTO::getId).collect(Collectors.toList());

        Collections.sort(aResourceIds);
        Collections.sort(bResourceIds);

        return aResourceIds.equals(bResourceIds);
    }

    @Autowired
    private UserSessionFacade userSessionFacade;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private RoleInfoService roleInfoService;


    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private ParticipantInfoService participantInfoService;

    @Autowired
    private RoleInfoDTOConverter roleInfoDTOConverter;
}

